图片(Image)

Flutter 中加载图片的控件是 Image,图片来源可以是 asset文件网络以及内存

图片来源的不同,加载图片的方式也不同,Flutter 提供了一个接口 ImageProvider,它是一个抽象类,定义了图片数据获取的接口的 load() 方法,不同的来源,需要实现不同的 ImageProvider 的实现类:

  • AssetImage ,用于加载 Asset 中的图片
  • NetworkImage,用于加载网络图片
  • FileImage,用于加载存储中的图片文件
  • MemoryImage,用于加载内存中的文件

看一下源码:

  const Image({
    Key key,
    @required this.image,
    this.frameBuilder,    
    this.loadingBuilder,
    this.semanticLabel,    //图像的语义描述,用于向Andoid上的TalkBack和iOS上的VoiceOver提供图像描述
    this.excludeFromSemantics = false,    //是否启用图像的语义描述
    this.width,    //控件宽度
    this.height,    //控件高度
    this.color,    //如果为非null,则使用colorBlendMode将此颜色与每个图像像素混合
    this.colorBlendMode,    //用于将color与此图像组合。
    this.fit,    //图片如何在Image控件中显示
    this.alignment = Alignment.center,    //对齐方式
    this.repeat = ImageRepeat.noRepeat,    //当图片没完全覆着Image时,如何绘制未覆盖的任何部分,默认值为noRepeat
    this.centerSlice,    //指定中心区域进行九个补丁图像,在中心切片内的图像区域将水平和垂直拉伸,以使图像适合其目的地。
    this.matchTextDirection = false,    //是否在TextDirection的方向上绘制图像。
    this.gaplessPlayback = false,    //当图像提供者发生变化时,是继续显示旧图像,默认不显示!
    this.filterQuality = FilterQuality.low,    //图像过滤器的质量级别。(渲染模式的质量)
  })

属性的详细解释请看来自这里 CSDN - 陈英有 - Flutter Image 参数详解,请移步原作者,这里仅作备份,以防作者删除。

  1. semanticLabel 是用于向安卓上的 TalkBack 和苹果上的 VoiceOver 提供图像描述

    1. talkback 是一款由谷歌官方开发的系统软件,它的定位是帮助盲人或者视力有障碍的用户提供语言辅助
    2. Voiceover 功能是苹果公司推出的一种语音辅助程序
  2. fit 用来控制图片如何在 Image 控件中显示,下面是这个属性的选项:

    1. BoxFit.fill

      图片按照指定的大小在 Image 中显示,拉伸显示图片,不保持原比例,填满 Image

    2. BoxFit.contain

      以原图正常显示为目的,如果原图大小大于 Image 的 size,就按照比例缩小原图的宽高,居中显示在 Image 中。如果原图 size 小于 Image 的 size,则按比例拉升原图的宽和高,填充 Image 一边并居中显示。

    3. BoxFit.cover

      以原图填满 Image 为目的,如果原图 size 大于 Image 的 size,按比例缩小,居中显示在 Image上。如果原图 size 小于 Image 的size,则按比例拉升原图的宽和高,填充 Image 居中显示。

    4. BoxFit.fitWidth

      以原图正常显示为目的,如果原图宽大小大于(小于)Image 的宽,就缩小(放大)原图的宽与 Image 一致,居中显示在 Image 中。

    5. BoxFit.fitHeight

      以原图正常显示为目的,如果原图高大小大于(小于)Image 的高,就缩小(放大)原图的高与 Image 一致,居中显示在 Image 中。

    6. BoxFit.none

      保持原图的大小,显示在 Image 的中心。当原图的 size 大于 Image 的 size 时,多出来的部分被截掉

    7. BoxFit.scaleDown

      以原图正常显示为目的,如果原图大小大于 Image 的 size,就按照比例缩小原图的宽高,居中显示在 Image 中。如果原图 size 小于 Image 的 size,则不做处理居中显示图片。

  3. repeat 用来设置当图片没完全覆着 Image 时,如何绘制未覆盖的任何部分,默认值为 noRepeat,有以下值可选:

    1. ImageRepeat.repeat

      在 x 和 y 方向上重复图像,直到填充框。

    2. ImageRepeat.repeatX

      在 x 方向上重复图像,直到水平填充框

    3. ImageRepeat.repeatY

      在 y 方向重复图像,直到垂直填充框

    4. ImageRepeat.noRepeat

      将未覆盖部分保持透明


从 Asset 中加载图片

我们知道,当我们的 App 打包时,Asset 目录中的文件是不进行压缩的,在 asset 目录我们经常会放一些基本数据(例如 json 文件),一些图片和图片之类的。

源码就不看了,和 Image 差不多,之多了一个 name 属性,用于指定图片名称。

在 Flutter 中如何访问它们呢?还记得之前的章节中的自定义 Text 字体吗?加载 Asset 图片和自定义字体步骤差不多:

  1. pubspec.yaml 文件中指定 asset 目录资源的位置

    需要注意 的是,这个 asset 目录和 Android 项目中的 assets 目录不是一回事,需要自己创建目录,并且对于目录的名称是没有要求的,不过通常我们会在 pubspec.yaml 同级目录创建一个 assets 目录,然后再在这个目录里划分 imagesfonts 之类的。例如目录划分是这样的:

    你的 APP 
        |- assets
        |     |- images
        |         |- icon.png
        |     |- fonts
        |          |- xxxxx
        |- pubspec.yaml
    

    pubspec.yaml 中就可以这样声明:

    flutter:
      assets:
        - assets/images/icon.png
    
  2. 然后就可以使用图片了:

    Image(image: AssetImage("assets/images/icon.png"), width: 100.0),
    

    Flutter 还提供了一种简便的方式:

    Image.asset("assets/images/icon.png", width: 100.0),
    

从网络中加载图片

源码和 Image 也基本类似,只是多了 srcheaders 属性,前者用于标识图片路径,后者用于标识请求图片时自定义的 HTTP 请求参数。

Image.network(
    "https://www.li-xyz.com/content/images/2019/08/2449319331.png",
    width: 100.0),
Image(
    image: NetworkImage(
        "https://www.li-xyz.com/content/images/2019/08/2449319331.png",
    ),
    width: 100,
),

从文件加载图片

其源码和 Image 类似,只是多了一个 File 属性,它是一个对象,用于表示图片的文件。

这里上一个例子,里面用到了 image_picker 包,以后会讲到:

class _FileImageDemoState extends State<MyHomePage> {
  File _image;

  Future getImage() async {
    var image = await ImagePicker.pickImage(source: ImageSource.gallery);

    setState(() {
      _image = image;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Center(
          child: _image == null
              ?  Text('您还未选择任何图片.')
              :  Image.file(_image,scale: 0.5,fit: BoxFit.cover,),
        ),
        FlatButton(
            onPressed: getImage,
            child: Text('点击选择图片',style: TextStyle(color: Colors.white),),
            color: Colors.lightBlue
        )
      ],
    );
  }
}

加载内存中的图片

主要解析 bytes 参数,其他和 Image 一致!

bytesUint8List 获取的 ImageStream

class _MemoryImageDemoState extends State<MyHomePage> {
  Uint8List bytes;

  void initState() {
    super.initState();
    rootBundle.load('assets/images/icon.png').then((data) {
      if (mounted) {
        setState(() {
          bytes = data.buffer.asUint8List();
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    final decoration =  BoxDecoration(
      image: bytes == null
          ? null
          :  DecorationImage(
        image:  MemoryImage(bytes,scale: 1.0),
      ),
    );
    return Container(
      width: 300.0,
      height: 300.0,
      decoration: decoration,
    );
  }
}

图标(ICON)

Flutter中,可以像Web开发一样使用 iconfonticonfont字体图标,它是将图标做成字体文件,然后通过指定不同的字符而显示不同的图片。

在字体文件中,每一个字符都对应一个位码,而每一个位码对应一个显示字形,不同的字体就是指字形不同,即字符对应的字形是不同的。而在 iconfont 中,只是将位码对应的字形做成了图标,所以不同的字符最终就会渲染成不同的图标。

在 Flutter 开发中,iconfont 和图片相比有如下优势:

  1. 体积小:可以减小安装包大小。
  2. 矢量的:iconfont 都是矢量图标,放大不会影响其清晰度。
  3. 可以应用文本样式:可以像文本一样改变字体图标的颜色、大小对齐等。
  4. 可以通过 TextSpan 和文本混用。
使用Material Design字体图标

Flutter默认包含了一套Material Design的字体图标,在pubspec.yaml文件中的配置如下

flutter:
  uses-material-design: true

Material Design所有图标可以在其官网查看:https://material.io/tools/icons/

我们看一个简单的例子:

String icons = "";
// accessible: &#xE914; or 0xE914 or E914
icons += "\uE914";
// error: &#xE000; or 0xE000 or E000
icons += " \uE000";
// fingerprint: &#xE90D; or 0xE90D or E90D
icons += " \uE90D";

Text(icons,
  style: TextStyle(
      fontFamily: "MaterialIcons",
      fontSize: 24.0,
      color: Colors.green
  ),
);

运行效果如图3-21所示:

图3-21

通过这个示例可以看到,使用图标就像使用文本一样,但是这种方式需要我们提供每个图标的码点,这并对开发者不友好,所以,Flutter封装了IconDataIcon来专门显示字体图标,上面的例子也可以用如下方式实现:

Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
    Icon(Icons.accessible,color: Colors.green,),
    Icon(Icons.error,color: Colors.green,),
    Icon(Icons.fingerprint,color: Colors.green,),
  ],
)

Icons类中包含了所有Material Design图标的IconData静态变量定义。

使用自定义字体图标

我们也可以使用自定义字体图标。iconfont.cn上有很多字体图标素材,我们可以选择自己需要的图标打包下载后,会生成一些不同格式的字体文件,在Flutter中,我们使用ttf格式即可。

假设我们项目中需要使用一个书籍图标和微信图标,我们打包下载后导入:

  1. 导入字体图标文件;这一步和导入字体文件相同,假设我们的字体图标文件保存在项目根目录下,路径为"fonts/iconfont.ttf":

    fonts:
      - family: myIcon  #指定一个字体名
        fonts:
          - asset: fonts/iconfont.ttf
    
  2. 为了使用方便,我们定义一个MyIcons类,功能和Icons类一样:将字体文件中的所有图标都定义成静态变量:

    class MyIcons{
      // book 图标
      static const IconData book = const IconData(
          0xe614, 
          fontFamily: 'myIcon', 
          matchTextDirection: true
      );
      // 微信图标
      static const IconData wechat = const IconData(
          0xec7d,  
          fontFamily: 'myIcon', 
          matchTextDirection: true
      );
    }
    
  3. 使用

    Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Icon(MyIcons.book,color: Colors.purple,),
        Icon(MyIcons.wechat,color: Colors.green,),
      ],
    )
    

    运行后效果如图3-22所示:

    图3-22

results matching ""

    No results matching ""